package edu.hcmus.sow.service;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import edu.hcmus.sow.dao.ClientDAO;
import edu.hcmus.sow.dao.ProjectDAO;
import edu.hcmus.sow.dao.TaskAttachmentDAO;
import edu.hcmus.sow.dao.TaskCategoryDAO;
import edu.hcmus.sow.dao.TaskCommentDAO;
import edu.hcmus.sow.dao.TaskDAO;
import edu.hcmus.sow.dao.TaskStatusDAO;
import edu.hcmus.sow.dao.TaskWorkLogDAO;
import edu.hcmus.sow.dao.UserDAO;
import edu.hcmus.sow.dao.UserProfileDAO;
import edu.hcmus.sow.domain.Client;
import edu.hcmus.sow.domain.Project;
import edu.hcmus.sow.domain.Task;
import edu.hcmus.sow.domain.TaskAttachment;
import edu.hcmus.sow.domain.TaskCategory;
import edu.hcmus.sow.domain.TaskComment;
import edu.hcmus.sow.domain.TaskStatus;
import edu.hcmus.sow.domain.TaskWorkLog;
import edu.hcmus.sow.domain.User;
import edu.hcmus.sow.domain.UserProfile;
import edu.hcmus.sow.utils.SecurityUtil;
import edu.hcmus.sow.utils.StringUtil;

@Service
@Transactional
public class TaskService {

   @Autowired
   TaskDAO taskDAO;

   @Autowired
   UserService userService;

   @Autowired
   ClientDAO clientDAO;

   @Autowired
   ProjectDAO projectDAO;

   @Autowired
   TaskStatusDAO taskStatusDAO;

   @Autowired
   TaskCommentDAO taskCommentDAO;

   @Autowired
   UserDAO userDAO;

   @Autowired
   TaskWorkLogDAO taskWorkLogDAO;

   @Autowired
   TaskCategoryDAO taskCategoryDAO;

   @Autowired
   UserProfileDAO userProfileDAO;

   @Autowired
   TaskAttachmentDAO taskAttachmentDAO;

   @Autowired
   RepositoryService repositoryService;

   // -----------------------------------------------------------------------
   // Task
   // -----------------------------------------------------------------------

   // get the number of each task in task.jsp
   public List<Integer> getNumberCommentOfEachTask(List<Task> tasks) {
      List<Integer> list = new ArrayList<Integer>();
      for (int i = 0; i < tasks.size(); i++) {
         Integer taskID = tasks.get(i).getId();
         Integer count = taskCommentDAO.getNumberCommentOfTask(taskID);
         list.add(count);

      }
      return list;
   }

   // get all task in project ID
   public List<Task> getByProjectID(Integer id) throws DataAccessException {

      List<Task> list = taskDAO.getTaskListByProject(id);
      return list;
   }

   // get completedTaskList
   public List<Task> getCompletedTaskListByProject(Integer projectID, Integer time) throws DataAccessException {

      List<Task> list = taskDAO.getCompletedTaskListByProject(projectID, time);
      return list;
   }

   public Task findByID(Integer id) {
      Task task = taskDAO.findByID(id);
      return task;
   }

   public Task saveTask(Task task) {
      if (task.getId() != null) {
         task = taskDAO.merge(task);
      } else {
         task = taskDAO.persist(task);
      }
      return task;
   }

   public Integer createTask(Integer projectID, String title, String description, Integer assignTo,
         Integer projectAssigned, Integer categoryID, String dueDate, String estHours) {
      // get current client
      // int clientID = SecurityUtil.getCurrentClient();
      // Client client = clientDAO.findById(clientID);

      // get logged in user
      int userID = SecurityUtil.getCurrentLoggedinUserID();
      User user = userService.getUserByID(userID);

      // get user Assigned to:
      User userAssign = userService.getUserByID(assignTo);

      // get project
      Project project = projectDAO.findById(projectID);

      // get category
      TaskCategory category;
      if (categoryID != null)
         category = taskCategoryDAO.findById(categoryID);
      else
         category = null;

      Task task = new Task();

      task.setTitle(title);
      task.setDescription(description);
      task.setOriginalEstimate(0);

      task.setAdjustedEstimate(0);

      /*
       * if (dueDate != "")
       * task.setDueDate(StringUtil.convertStringToCalendar(dueDate)); else
       */
      //task.setDueDate(Calendar.getInstance());

      if (category != null)
         task.setTaskCategory(category);
      if (project != null)
         task.setProject(project);
      if (userAssign != null)
         task.setUserByAssignedTo(userAssign);

      task.setCreatedDate(Calendar.getInstance());
      task.setUserByCreatedBy(user);
      task.setUpdatedDate(Calendar.getInstance());
      task.setUserByUpdatedBy(user);

      // Set status=2 is not complete = this task has been created ...
      task.setTaskStatus(taskStatusDAO.findById(4));
      task = saveTask(task);
      System.out.println("Task is created");
      return task.getId();
   }

   public void deleteTask(Integer taskID) {
      Task task = taskDAO.findByID(taskID);
      if (task.getId() != null) {
         taskDAO.delete(task);
      }
   }

   // -----------------------------------------------------------------------
   // Task progress bar
   // -----------------------------------------------------------------------

   // Update Adjusted Estimate -- When user pull progress bar of Task
   public void updateProgressOfTask(Integer taskID, Integer progress) throws DataAccessException {
      Task task = findByID(taskID);
      // get logged in user
      int userID = SecurityUtil.getCurrentLoggedinUserID();
      User user = userService.getUserByID(userID);
      if (task == null) {
         return;
      } else {
         if (progress == 100) {
            TaskStatus stt = taskStatusDAO.findById(1);
            task.setTaskStatus(stt);
            task.setAdjustedEstimate(progress);
            task.setUpdatedDate(Calendar.getInstance());
            task.setUserByUpdatedBy(user);
         } else {
            task.setAdjustedEstimate(progress);
            task.setUpdatedDate(Calendar.getInstance());
            task.setUserByUpdatedBy(user);
            TaskStatus stt = taskStatusDAO.findById(2);
            task.setTaskStatus(stt);
         }
      }
   }

   public void markComplete(Integer taskID, Integer projectID) {

      // get Task Completed Status
      TaskStatus taskStt = taskStatusDAO.findById(1);
      // get Task
      Task task = taskDAO.findByID(taskID);
      if (task != null) {
         // set Status
         task.setTaskStatus(taskStt);
         // set progress of task
         task.setAdjustedEstimate(100);

         task.setUpdatedDate(Calendar.getInstance());
         // get logged in user
         int userID = SecurityUtil.getCurrentLoggedinUserID();
         User user = userService.getUserByID(userID);

         task.setUserByUpdatedBy(user);
         // update task
         saveTask(task);
      }
   }

   // -----------------------------------------------------------------------
   // Task comment
   // -----------------------------------------------------------------------

   // get taskComment list by task ID
   public List<TaskComment> getTaskCommentList(Integer taskID) throws DataAccessException {
      List<TaskComment> list = taskCommentDAO.getCommentsList(taskID);
      return list;
   }

   public void addComment(Integer taskID, String content) {
      // TODO Auto-generated method stub
      TaskComment taskComment = new TaskComment();

      int userID = SecurityUtil.getCurrentLoggedinUserID();
      // get Task
      Task task = taskDAO.findByID(taskID);
      User userCreated = userDAO.findById(userID);
      if (task == null || userCreated == null)
         return;
      else {

         taskComment.setTask(task);
         taskComment.setUser(userCreated);
         taskComment.setContent(content);
         taskComment.setCreatedDate(Calendar.getInstance());
         taskComment.setUpdatedDate(Calendar.getInstance());

         if (taskComment.getId() != null) {
            taskCommentDAO.merge(taskComment);
         } else
            taskCommentDAO.persist(taskComment);

      }
   }

   public void deleteComment(Integer commentID) {
      TaskComment taskComment = taskCommentDAO.findById(commentID);
      if (taskComment.getId() != null) {
         taskCommentDAO.delete(taskComment);
      }
   }

   // -----------------------------------------------------------------------
   // Task work log
   // -----------------------------------------------------------------------

   public List<TaskWorkLog> getTaskWorkLogReports(Integer userID, Integer projectID, String fromDate, String toDate) {
      User user = userDAO.findById(userID);
      Project project = projectDAO.findById(projectID);
      Calendar from = StringUtil.convertStringToCalendar(fromDate);
      Calendar to = StringUtil.convertStringToCalendar(toDate);
      System.out.println(fromDate);
      System.out.println(toDate);
      List<TaskWorkLog> list = taskWorkLogDAO.getTaskWorkLogReports(user, project, from, to);
      return list;
   }

   public List<TaskWorkLog> getTaskWorkLogLists(Integer taskID) {
      List<TaskWorkLog> list = taskWorkLogDAO.getListsByTaskID(taskID);
      return list;
   }

   public void addTaskWorkLog(Integer taskID, String loggedDate, Integer person, Integer timeSpent, String note) {
      Task task = taskDAO.findByID(taskID);
      User user = userDAO.findById(person);
      try {
         if (task.getId() == null || user.getId() == null) {
            
            return;
         } else {
            TaskWorkLog twl = new TaskWorkLog();
            Calendar cal = StringUtil.convertStringToCalendar(loggedDate);
            twl.setLoggedDate(cal);
            twl.setNote(note);
            twl.setTask(task);
            twl.setTimeSpent(timeSpent);
            twl.setUser(user);
            if (twl.getId() != null) {
               twl = taskWorkLogDAO.merge(twl);
            } else {
               twl = taskWorkLogDAO.persist(twl);
            }
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
   }

   public void deleteTaskWorkLog(Integer id) {
      TaskWorkLog twl = taskWorkLogDAO.findById(id);
      if (twl != null) {
         taskWorkLogDAO.delete(twl);
      }
   }

   // -----------------------------------------------------------------------
   // Edit Pop up..
   // -----------------------------------------------------------------------

   // get Projects
   public List<Project> getProjects() {
      List<Project> list = projectDAO.findAll();
      return list;
   }

   // Update task in Pop up
   public void updateTask(Integer taskID, String title, String description, Integer assignID, Integer categoryID,
         Integer projectID, String estimatedHours, String dueDate) {

      // get User is assigned by assignID
      User assign = userDAO.findById(assignID);

      // get category by id
      TaskCategory category = taskCategoryDAO.findById(categoryID);

      // get project by projectID
      Project project = projectDAO.findById(projectID);

      Task task = taskDAO.findById(taskID);

      task.setTitle(title);
      task.setDescription(description);
      if (estimatedHours != "") {
         int estHours = StringUtil.convertTimeSpentToInt(estimatedHours);
         task.setOriginalEstimate(estHours);
      }
      if (dueDate != "") {
         task.setDueDate(StringUtil.convertStringToCalendar(dueDate));
      }
      if (assign != null)
         task.setUserByAssignedTo(assign);
      if (category != null)
         task.setTaskCategory(category);
      if (project != null)
         task.setProject(project);
      saveTask(task);
   }

   // get all email by userIDs
   public List<String> getEmailByUserID(List<Integer> userIDs) {
      List<String> emailList = new ArrayList<String>();
      for (int i = 0; i < userIDs.size(); i++) {
         User user = userDAO.findById(userIDs.get(i));
         UserProfile userProFile = userProfileDAO.getByUserID(user.getId());
         if (userProFile != null) {
            if (!userProFile.getEmail().equals("0")) {
               String emailTo = userProFile.getEmail();
               emailList.add(emailTo);
            }
         }
      }
      return emailList;
   }

   // -----------------------------------------------------------------------
   // Task categories
   // -----------------------------------------------------------------------

   // get Categories
   public List<TaskCategory> getCategories() {
      List<TaskCategory> list = taskCategoryDAO.findAll();
      return list;
   }

   public void saveTaskCategory(TaskCategory category) {
      if (category.getId() != null)
         taskCategoryDAO.merge(category);
      else
         taskCategoryDAO.persist(category);
   }

   public void addCategories(String name, String description) {
      TaskCategory category = new TaskCategory();

      int clientID = SecurityUtil.getCurrentClient();
      Client client = clientDAO.findById(clientID);

      // get logged in user
      int userID = SecurityUtil.getCurrentLoggedinUserID();
      User user = userService.getUserByID(userID);

      category.setClient(client);
      category.setName(name);
      category.setDescription(description);
      category.setUserByCreatedBy(user);
      category.setUserByUpdatedBy(user);
      category.setUpdatedDate(Calendar.getInstance());
      category.setStatus("1");

      System.out.println(user.getUsername());
      saveTaskCategory(category);
   }

   public void updateTaskCategory(Integer taskCategoryID, String name, String description) {

      TaskCategory category = taskCategoryDAO.findById(taskCategoryID);

      // get logged in user
      int userID = SecurityUtil.getCurrentLoggedinUserID();
      User user = userService.getUserByID(userID);

      if (category != null) {
         category.setName(name);
         category.setDescription(description);
         category.setUserByUpdatedBy(user);
         category.setUpdatedDate(Calendar.getInstance());

         saveTaskCategory(category);
      }
   }

   public void deleteCategory(Integer id) {
      TaskCategory category = taskCategoryDAO.findById(id);
      if (category != null) {
         taskCategoryDAO.delete(category);
      }
   }

   // Upload attachment files
   public TaskAttachment findFileByName(String fileName) {
      TaskAttachment taskAttachment = taskAttachmentDAO.findByName(fileName);
      return taskAttachment;
   }

   public TaskAttachment saveTaskAttachment(TaskAttachment taskAttachment) {
      if (taskAttachment.getId() != null) {
         taskAttachment = taskAttachmentDAO.merge(taskAttachment);
      } else
         taskAttachment = taskAttachmentDAO.persist(taskAttachment);
      return taskAttachment;
   }

   public List<TaskAttachment> getTaskAttacments(Integer taskID) {
      List<TaskAttachment> lists = taskAttachmentDAO.getAttachments(taskID);
      return lists;
   }

   public TaskAttachment getTaskAttachmentByID(Integer id) {
      return taskAttachmentDAO.findById(id);
   }

   public void deleteTaskAttachment (Integer attachmentID, String rk){
      
      //delete rk in Cassandra
      repositoryService.deleteFile(rk);
      
      //delete attachment in My SQL
      TaskAttachment attach = taskAttachmentDAO.findById(attachmentID);
      if (attach != null)
         taskAttachmentDAO.delete(attach);
   }
}
